package cn.nfwx.tv.okhttp;


import android.content.Context;

import org.json.JSONObject;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import cn.nfwx.tv.callback.ResponseListener;
import cn.nfwx.tv.callback.ResponseWithFailListener;
import cn.nfwx.tv.conts.Constants;
import cn.nfwx.tv.util.ToolUtil;
import okhttp3.Call;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.Callback;
import okhttp3.Dispatcher;

/**
 * Created by zb.liu on 2017/10/27.
 */

public class CustomOkHttpClient {

    private static final String TAG_LOG = "CustomOkHttpClient";
    private final static String CHARSET = "UTF-8";
    private final static MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");

    private static OkHttpClient okHttpClient;

    public static OkHttpClient getOkHttpClient() {
        if (okHttpClient == null) {
            synchronized (CustomOkHttpClient.class) {
                if (okHttpClient == null) {
                    okHttpClient = getNormalHttpClient();
                }
            }
        }
        return okHttpClient;
    }

    private static OkHttpClient getNormalHttpClient() {
        OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
        okHttpClientBuilder.connectTimeout(Constants.TIMEOUT, TimeUnit.MILLISECONDS);
        okHttpClientBuilder.writeTimeout(Constants.TIMEOUT, TimeUnit.MILLISECONDS);
        okHttpClientBuilder.readTimeout(Constants.TIMEOUT, TimeUnit.MILLISECONDS);

        return okHttpClientBuilder.build();
    }

    private static String urlEncode(String text) {
        try {
            return URLEncoder.encode(text, CHARSET);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();

            return text;
        }
    }

    public static void postObjectRequest(Context context, String url, String requestTag,
                                         ResponseListener<JSONObject> listener) {
        postObjectRequest(context, url, Constants.TIMEOUT, requestTag,
                listener);
    }

    public static void getObjectRequest(Context context, String url, String requestTag,
                                        ResponseListener<JSONObject> listener) {
        // bugly:#2037 java.lang.NullPointerException
        try {
            getObjectRequest(context, url, Constants.TIMEOUT, requestTag,
                    listener);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void getObjectRequest(Context context, String url, String requestTag,
                                        ResponseWithFailListener listener) {
        getObjectRequest(context, url, Constants.TIMEOUT, requestTag,
                listener);
    }

    public static void getObjectRequestWithHeader(Context context, final String url, String requestTag, String header,
                                                  final ResponseListener<String> listener) {

        Request request = new Request.Builder().url(url).tag(requestTag).header("Authorization", header).get().build();
        enqueue(url, request, listener);
    }


    public static void getObjectRequestWithHeader(Context context, final String url, String requestTag, String header,
                                                  final ResponseWithFailListener<String> listener) {

        Request request = new Request.Builder().url(url).tag(requestTag).header("Authorization", header).get().build();
        enqueue(url, request, listener);
    }


    public static void postObjectRequest(Context context, final String url,
                                         Map<String, String> params, String requestTag,
                                         final ResponseListener<JSONObject> listener) {
        // bugly:#2037 java.lang.NullPointerException
        try {
            postObjectRequest(context, url, params, Constants.TIMEOUT, requestTag,
                    listener);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void postObjectRequestWithHeader(Context context, final String url,
                                                   Map<String, String> params, String requestTag, String header,
                                                   final ResponseListener<String> listener) {
        postObjectRequestWithHeader(context, url, params, Constants.TIMEOUT, requestTag, header,
                listener);
    }

    public static void putObjectRequestWithHeader(Context context, final String url,
                                                  HashMap<String, String> params, String requestTag, String header,
                                                  final ResponseListener<JSONObject> listener) {
        // bugly:#2037 java.lang.NullPointerException
        try {
            putObjectRequestWithHeader(context, url, params, Constants.TIMEOUT, requestTag, header,
                    listener);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void postObjectRequest(Context context, String url, int timeout,
                                         String requestTag, ResponseListener<JSONObject> listener) {
        // bugly:#2037 java.lang.NullPointerException
        try {
            postObjectRequest(context, url, new HashMap<String, String>(), timeout, requestTag, listener);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected static void getObjectRequest(final Context context, final String url, int timeout, String requestTag,
                                           final ResponseWithFailListener listener) {

        Request request = new Request.Builder().url(url).tag(requestTag).build();

        enqueueStringObject(url, request, listener);
    }

    protected static void getObjectRequest(final Context context, final String url, int timeout, String requestTag,
                                           final ResponseListener<JSONObject> listener) throws Exception {

        Request request = new Request.Builder().url(url).tag(requestTag).get().build();

        enqueueJsonObject(url, request, listener);
    }

    public static void deleteObjectRequestWithBody(final Context context, final String url,
                                                   String body, String requestTag, String header,
                                                   final ResponseListener<String> listener) {
        MediaType JSON = MediaType.parse("application/json; charset=utf-8");
        RequestBody requestBody = RequestBody.create(JSON, body);
        Request request = new Request.Builder()
                .url(url)
                .header("Authorization", header)
                .tag(requestTag)
                .delete(requestBody)
                .build();
        enqueue(url, request, listener);
    }

    public static void deleteObjectRequestWithHeader(final Context context, final String url,
                                                     Map<String, String> paramMap, String requestTag, String header,
                                                     final ResponseListener<String> listener) {
        CustomOkHttpClient.cancleAll(requestTag);
        FormBody.Builder builder = new FormBody.Builder();

        if (paramMap != null && !paramMap.isEmpty()) {
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                builder.add(entry.getKey(), entry.getValue());
            }
        }

        Request request = new Request.Builder()
                .url(url)
                .header("Authorization", header)
                .tag(requestTag)
                .delete(builder.build())
                .build();
        enqueue(url, request, listener);
    }


    public static void postObjectRequest(final Context context, final String url,
                                         Map<String, String> paramMap, int timeout, String requestTag,
                                         final ResponseListener<JSONObject> listener) throws Exception {
        FormBody.Builder builder = new FormBody.Builder();
        if (paramMap != null && !paramMap.isEmpty()) {
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                if (entry.getKey() != null && entry.getValue() != null) {
                    builder.add(entry.getKey(), entry.getValue());
                }
            }
        }

        Request request = new Request.Builder()
                .url(url)
                .tag(requestTag)
                .post(builder.build())
                .build();
        enqueueJsonObject(url, request, listener);
    }

    public static void postObjectRequest(final Context context, final String url,
                                         Map<String, String> paramMap, int timeout, String requestTag,
                                         final ResponseWithFailListener<JSONObject> listener) {
        FormBody.Builder builder = new FormBody.Builder();
        if (paramMap != null && !paramMap.isEmpty()) {
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                builder.add(entry.getKey(), entry.getValue());
            }
        }

        Request request = new Request.Builder()
                .url(url)
                .tag(requestTag)
                .post(builder.build())
                .build();
        enqueueJsonObject(url, request, listener);
    }


    public static void putObjectRequestWithHeader(final Context context, final String url,
                                                  Map<String, String> paramMap, int timeout, String requestTag, String header,
                                                  final ResponseListener<JSONObject> listener) throws Exception {
        FormBody.Builder builder = new FormBody.Builder();
        if (paramMap != null && !paramMap.isEmpty()) {
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                builder.add(entry.getKey(), entry.getValue());
            }
        }
        Request request = new Request.Builder()
                .url(url)
                .tag(requestTag)
                .header("Authorization", header)
                .put(builder.build())
                .build();
        enqueueJsonObject(url, request, listener);
    }

    public static void putObjectRequestWithHeader(final Context context, final String url,
                                                  Map<String, String> paramMap, int timeout, String requestTag, String header,
                                                  final ResponseWithFailListener<JSONObject> listener) {
        FormBody.Builder builder = new FormBody.Builder();
        if (paramMap != null && !paramMap.isEmpty()) {
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                builder.add(entry.getKey(), entry.getValue());
            }
        }
        Request request = new Request.Builder()
                .url(url)
                .tag(requestTag)
                .header("Authorization", header)
                .put(builder.build())
                .build();
        enqueueJsonObject(url, request, listener);
    }

    public static void postObjectRequestWithHeader(final Context context, final String url,
                                                   Map<String, String> paramMap, int timeout, String requestTag, String header,
                                                   final ResponseListener<String> listener) {
        FormBody.Builder builder = new FormBody.Builder();
        if (paramMap != null && !paramMap.isEmpty()) {
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                builder.add(entry.getKey(), entry.getValue());
            }
        }
        Request request = new Request.Builder()
                .url(url)
                .tag(requestTag)
                .header("Authorization", header)
                .post(builder.build())
                .build();
        enqueue(url, request, listener);
    }


    public static void enqueueJsonObject(final String url, Request request, final ResponseListener listener) {
        Call call = getOkHttpClient().newCall(request);

        call.enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) throws IOException {


                String tag = (String) call.request().tag();
                if (listener != null) {
                    if (response.isSuccessful()) {
                        try {
                            listener.onResponse(tag, new JSONObject(ToolUtil.inputStream2String(response.body().byteStream())));
                        } catch (Exception e) {
                            listener.onError(tag, e);
                        }
                    } else {
                        listener.onError(tag, new IllegalArgumentException("" + response));
                    }

                    listener.onFinish();
                }
            }

            @Override
            public void onFailure(Call call, IOException e) {
                String tag = (String) call.request().tag();
                if (listener != null) {
                    if (!call.isCanceled()) {
                        listener.onError(tag, e);
                    }
                    listener.onFinish();
                }
            }
        });
    }

    public static void enqueueStringObject(final String url, Request request, final ResponseWithFailListener listener) {
        Call call = getOkHttpClient().newCall(request);

        call.enqueue(new Callback() {

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String tag = (String) call.request().tag();
                if (listener != null) {
                    if (response.isSuccessful()) {
                        try {
                            listener.onResponse(tag, ToolUtil.inputStream2String(response.body().byteStream()));
                        } catch (Exception e) {
                            listener.onError(tag, e);
                        }
                    } else {
                        listener.onFail(tag, response.body().string());
                    }

                    listener.onFinish();
                }
            }

            @Override
            public void onFailure(Call call, IOException e) {
                String tag = (String) call.request().tag();
                if (listener != null) {
                    if (!call.isCanceled()) {
                        listener.onError(tag, e);
                    }
                    listener.onFinish();
                }
            }
        });
    }

    public static void enqueueJsonObject(final String url, Request request, final ResponseWithFailListener listener) {
        Call call = getOkHttpClient().newCall(request);

        call.enqueue(new Callback() {

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String tag = (String) call.request().tag();
                if (listener != null) {
                    if (response.isSuccessful()) {
                        try {
                            listener.onResponse(tag, new JSONObject(ToolUtil.inputStream2String(response.body().byteStream())));
                        } catch (Exception e) {
                            listener.onError(tag, e);
                        }
                    } else {
                        listener.onFail(tag, response.body().string());
                    }

                    listener.onFinish();
                }
            }

            @Override
            public void onFailure(Call call, IOException e) {
                String tag = (String) call.request().tag();
                if (listener != null) {
                    if (!call.isCanceled()) {
                        listener.onError(tag, e);
                    }
                    listener.onFinish();
                }
            }
        });
    }

    public static void enqueue(final String url, Request request, final ResponseWithFailListener<String> listener) {
        Call call = getOkHttpClient().newCall(request);

        call.enqueue(new Callback() {

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                String tag = (String) call.request().tag();
                if (listener != null) {
                    if (response.isSuccessful()) {
                        listener.onResponse(tag, response.body().string());
                    } else {
                        listener.onError(tag, new IllegalArgumentException("" + response));
                    }

                    listener.onFinish();
                }
            }

            @Override
            public void onFailure(Call call, IOException e) {

                String tag = (String) call.request().tag();
                if (listener != null) {
                    if (!call.isCanceled()) {
                        listener.onError(tag, e);
                    }
                    listener.onFinish();
                }

            }
        });
    }


    public static void enqueue(final String url, Request request, final ResponseListener<String> listener) {
        Call call = getOkHttpClient().newCall(request);

        call.enqueue(new Callback() {

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                String tag = (String) call.request().tag();
                if (listener != null) {
                    if (response.isSuccessful()) {
                        listener.onResponse(tag, response.body().string());
                    } else {
                        listener.onError(tag, new IllegalArgumentException("" + response));
                    }

                    listener.onFinish();
                }
            }

            @Override
            public void onFailure(Call call, IOException e) {

                String tag = (String) call.request().tag();
                if (listener != null) {
                    if (!call.isCanceled()) {
                        listener.onError(tag, e);
                    }
                    listener.onFinish();
                }

            }
        });
    }

    public static void doGet(String url, String tag, Callback callBack) {
        CustomOkHttpClient.cancleAll(tag); // 防止多次点击
        final Request request = new Request.Builder().url(url).tag(tag).method("GET", null).build();
        Call call = getOkHttpClient().newCall(request);
        call.enqueue(callBack);
    }

    public static void cancleAll() {
        Dispatcher dispatcher = getOkHttpClient().dispatcher();
        for (Call call : dispatcher.queuedCalls()) {
            call.cancel();
        }
        for (Call call : dispatcher.runningCalls()) {
            call.cancel();
        }
    }

    public static void cancleAll(Object tag) {
        if (tag == null) {
            return;
        }
        Dispatcher dispatcher = getOkHttpClient().dispatcher();
        for (Call call : dispatcher.queuedCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
        for (Call call : dispatcher.runningCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
    }
}
